我们知道,props,state,context变化,会引起react 组件重新渲染?但是在实际项目中,比如说表格里面的操作了,点击编辑按钮,然后进入一个form页面,form提交之后回到原页面,此时怎么让表格更新呢?还有很多种场景啊,请你使用原生的react或者react相关库来说明

 

你问到的是真实项目里面 React 状态管理的核心问题

很多 React 初学者知道:

props 变化 → re-render state 变化 → re-render context 变化 → re-render

但是实际业务:

这些场景里面:

到底是谁触发 re-render?数据怎么同步?

这才是工程实践。

下面我用几个真实项目模式说明。

 

场景 1:Table 页面 → Edit 页面 → 返回 → Table 更新

这是最经典的 CRUD 场景。

例如:

问题:

返回以后,React 怎么知道重新请求数据?

方案一:父组件 state 控制(原生 React)

最简单:

代码:

编辑:

流程:

这里真正触发 React 更新的是:

不是:

React 根本不知道数据库变了。

非常重要的一句话

React 不会监听你的数据库变化。数据库更新不会导致组件重新渲染,必须通过状态更新或者重新获取数据,让 React 感知变化。

 

场景 2:使用 React Query(真实项目最常见)

大型项目一般不会手写:

而是 TanStack Query。

例如:

编辑:

流程:

这里触发 React 更新的是 React Query 内部:

最终还是 state change

这也是企业项目最常见方式

例如:

两个组件 不需要 props 传来传去。

 

场景 3:Context 全局刷新

比如用户权限:

Context:

登录:

所有:

组件重新 render。

 

但是注意 Context 不适合表格数据。例如:

修改一个用户,所有消费者重新 render。性能不好。

 

场景 4:URL 驱动状态(Next.js 常用)

例如Table:

Next.js:

当URL:

变化,React发现 hook 返回值变化。所以组件重新 render。

例如:

流程:

 

场景 5:Server Component + Next.js 16

如果是 App Router:

例如:

现在编辑:

Server Action:

然后:

这里不是 React state。

而是 Next.js 重新执行 Server Component。

 

场景 6:局部更新(Optimistic UI)

例如删除:

点击:

不要等服务器。

立即:

React 19:

流程:

 

所以实际项目里面,Table 更新有哪些方式?

总结:

场景触发方式
父组件管理数据setState,将setState方法传递给子组件调用
React QueryinvalidateQueries / setQueryData
Redux/Zustandstore update
ContextProvider value change
URL 状态router.push / searchParams
Next Server ComponentrevalidatePath
Cache 数据revalidateTag
Optimistic UIuseOptimistic
WebSocketexternal store update

 

面试回答

如果面试官问:

How do you update a table after editing a record?

In React applications, updating the database itself does not trigger a re-render. The UI needs a state update or data revalidation mechanism. In small applications, I may lift the state up and call a refresh function after mutation. In production applications, I usually use React Query, where mutations invalidate related queries, causing the table data to refetch and update automatically. In Next.js App Router applications, Server Actions combined with revalidatePath or revalidateTag can trigger Server Components to regenerate and send updated RSC payloads.

 

最核心的理解

React re-render 的本质不是:

而是:

数据库只是数据存储。

React 只响应状态,不响应数据本身。

这也是为什么现代 React 项目会引入:

因为它们本质都是在解决:

"数据变化以后,如何让 React 知道并正确更新 UI。"

 

 

像Vue里面,开发的时候,我们可以使用后台直接创建菜单,react里面应该怎么做呢?

我从来没有实现这个功能,在vue里面也没有,而且vue里面的菜单组件搞得很复杂,而且路由系统也非常复杂,所以我以为react里面也应该会很复杂。

但其实react里面很简单,只需要从后端获取到菜单数据,然后渲染出来就行了,就这么简单。当然如果有固定的菜单项,可以写在前端代码里面,拿到数据之后拼接即可。

菜单页面更简单了,就是普通的table+CRUD页面而已。那菜单页面更新了之后,怎么通知菜单栏重新获取数据更新呢?这个也很简单,使用react query的方法即可。

权限怎么做呢?不同的角色、不同的权限会显示不同的菜单栏。

 

我之所以觉得很难,是因为我没有搞懂整个流程,我以为前端要处理一切,至少看vue里面的代码让我有这种感觉,vue里面确实太复杂了。

其实前端只需要获取数据、渲染菜单、保护路由而已。而后端数据才是唯一真相源。

 

 

 

还有哪些难点呢?

在实际企业级系统(CRM / ERP / SaaS / Admin Dashboard)中,除了 Permission-based Navigation(基于权限的导航系统),还有很多典型的工程难点。

下面只列项目级难点:

1. Permission-based Navigation(基于权限的导航系统)

 

2. Authentication & Authorization(认证与授权)

 

3. Multi-Tenant Architecture(多租户架构)

CRM 非常常见:

 

4. Large Data Table(大型数据表格)

CRM 高频:

 

5. Complex Form Management(复杂表单)

例如:

客户信息:

 

6. Data Synchronization(数据同步)

例如:

编辑用户以后列表更新:

相关:

 

7. Real-time Features(实时功能)

CRM 常见:

技术:

 

8. File Upload System(文件上传)

CRM 常见:

难点:

 

9. Search System(搜索系统)

例如:

客户搜索:

技术:

 

10. Audit Log System(审计日志)

企业系统非常重要:

记录:

例如:

 

11. Data Import / Export(数据导入导出)

CRM 高频:

 

12. Workflow Engine(工作流系统)

例如:

销售流程:

难点:

 

13. Notification System(通知系统)

包括:

 

14. Background Job System(后台任务)

例如:

导入 100 万客户。

不能:

直接阻塞。

需要:

技术:

 

15. Caching Strategy(缓存策略)

难点:

尤其:

Cache invalidation is one of the hardest problems in software engineering.

 

16. Performance Optimization(性能优化)

大型 CRM:

 

17. Internationalization(国际化)

国际 SaaS 常见:

 

18. Error Handling System(错误处理体系)

包括:

 

19. Data Validation(数据验证)

前后端:

技术:

 

20. Database Design(数据库设计)

CRM 核心:

 

21. Reporting & Analytics Dashboard(报表系统)

例如:

销售 Dashboard:

 

22. Audit & Compliance(合规)

企业客户常要求:

 

23. Deployment & Infrastructure(工程化)

包括:

 

24. Offline / Network Handling

例如:

移动 CRM:

 

25. Component Architecture(组件架构)

大型系统:


如果按照 Senior React / Next.js Full-stack 面试优先级 排序,我认为最高频的是:

这些基本就是企业级 CRM / SaaS 项目里最容易体现 Senior Engineer 能力的地方。

 

 

 

Permission-based Navigation 方案流程图

Permission-based Navigation(RBAC)整体架构

首先我会告诉面试官:

In enterprise applications, I usually implement Role-Based Access Control (RBAC). The backend is the source of truth for permissions, while the frontend is responsible for rendering menus and protecting routes based on the permission data returned by the server.

整个流程如下:

整个系统可以分成 四层

  1. Authentication(登录)
  2. Authorization(权限计算)
  3. Navigation(菜单渲染)
  4. Resource Protection(资源保护)

下面逐层解释。

 

第一层:Authentication(登录)

用户输入:

流程:

例如:

这里还没有权限

只是知道:当前登录的是谁。

 

第二层:Authorization(权限计算)

登录以后:

后端根据:

查询:

例如数据库:

roles:

permissions:

menus:

关系:

最终后端得到:

这里有一个非常重要的原则:

后端才是权限的唯一可信来源(Source of Truth)。

前端不要自己计算权限。

 

第三层:Navigation(动态菜单)

前端收到:

Layout:

Sidebar:

管理员:

销售:

所以菜单完全来自数据库。

而不是:

写死。也不是前端自己计算。

 

第四层:Route Protection(页面权限)

菜单隐藏不代表页面安全。

例如用户直接输入:

怎么办?

流程:

因此页面也必须验证:

而不是只依赖Sidebar。

 

第五层:Button Permission(按钮权限)

很多 CRM 不仅页面有权限。按钮也有权限。

例如 Customer 页面:

销售:

管理员:

客服:

按钮也是Permission。

例如:

前端根据 permission 决定 Render 哪个 Button。

route protection 和 button permission是怎么实现呢?前端要在页面里面写死setting:view这样的权限数据吗?然后Button里面也要写死 setting:view 这样的权限数据吗?

 

是的,前端通常需要引用 permission key,但是不会把权限逻辑写死在每个页面里,需要封装一些常量、方法之后再使用。

正确设计是:

 

按钮

不要这样写:

虽然能工作,但是项目大了会崩。

 

正确封装:

使用:

这样最起码不会在每个页面里面都写获取permission的代码,简单多了。

 

大型项目经常这样,这个就更简单了,组件使用起来是最清晰的:

实现:

 

页面

client components

例如:

ProtectedRoute 组件的代码:

流程:

server components

流程:

或者可以直接在proxy.js里面进行检查。

 

编写常量

一般都会编写常量到 permissions.ts 里面,方便管理、文件也可以拆分、而且有代码提示。

然后Button:

 

第六层:API Permission(真正的安全)

这是最重要的一层。

很多新人认为按钮隐藏就安全。其实不是。

例如攻击者直接:

如果后端不检查:

数据库一样删掉。

所以真正流程:

前端权限只负责体验,后端权限才负责安全。

 

整个 RBAC 流程总结

 

面试中加分的一句话

很多候选人会说:

"The frontend controls permissions."

这句话不准确。

更准确的说法是:

The frontend is responsible for rendering the UI based on permissions, while the backend is responsible for enforcing permissions. The backend is always the source of truth for authorization.

这句话在 Senior 面试里是一个比较重要的观点,因为它体现了你对安全边界(Security Boundary)的理解:前端负责展示(Presentation),后端负责授权(Authorization Enforcement)

 

 

 

Large data table 方案流程图

Large Data Table(大型数据表格) 是 Senior React / Next.js 面试非常高频的问题,尤其是在 CRM、ERP、后台管理系统中。

面试官通常不是想听:

“我用 TanStack Table。”

而是想知道:

下面按照 Senior Full-stack 面试回答方式 来讲。


假设 CRM 有:

整体流程:

第一层:为什么不能一次性加载全部数据?

很多新人方案:

然后:

假设 100 万条:

问题:

1. Network

传输巨大 JSON:

2. Browser memory

浏览器保存:

3. React rendering

React:

直接崩。

所以大型系统第一原则:

Never send all data to the client.

 

第二层:Server-side Pagination(服务端分页)

这是 CRM 最常见方案。

例如第一页:

流程:

数据库:

 

第三层:为什么不用 Client Pagination?

小数据例如 500 条可以:

但是大数据:

面试回答:

For large datasets, I prefer server-side pagination because fetching all records to the client increases network cost, memory usage, and rendering overhead.

 

第四层:Search 搜索怎么做?

例如输入:

不要:

因为数据不在客户端。

流程:

Frontend:

请求:

Backend:

 

第五层:Sorting 排序

例如点击:

不要:

因为数据不完整。

流程:

数据库:

 

第六层:Filter 筛选

例如 CRM:

流程:

例如 URL:

 

第七层:Table 状态管理

大型项目不要:

散落。

通常统一:

例如:

更成熟:

放 URL:

好处:

Next.js:

 

第八层:React Query 管理 Server State

企业项目通常不用:

而是:

例如:

更新:

 

第九层:避免大量 Row Render

假设 100 rows。

普通:

优化:

React.memo

Stable props

避免:

每次创建新引用。

使用:

 

第十层:Virtualization(虚拟滚动)

如果不是分页。

例如 Excel 类应用 10000 rows。

不要:

而是:

只渲染可见区域。

技术:

流程:

 

第十一层:导出大量数据

错误:

100 万数据,浏览器会卡死。

正确:

 

第十二层:完整企业级架构

最终:

 

面试回答(Senior)

如果面试官问:

How do you design a large data table for millions of records?

可以这样回答:

For large datasets, I avoid loading all records into the browser. I usually implement server-side pagination, filtering, and sorting. The table state is managed centrally and often synchronized with URL parameters so users can share and restore the same view. On the frontend, I use React Query to manage server state and caching, and I optimize rendering with memoization or virtualization when necessary. On the backend side, I make sure database queries are optimized with proper indexes and permission checks. For extremely large exports, I use background jobs instead of blocking the request.